from functools import lru_cache
import datetime
import time
import re


class Dispatcher:
    names = {'remote', 'datetime', 'protocol',
             'status', 'size', 'url', 'useragent'}

    def __init__(self, filename):
        self.filename = filename
        self.res_dict = {}  # 将所有的分组结果都存到字典里

    def run(self):
        regex = re.compile(
            '(?P<remote>[0-9\.]+) - - \[(?P<datetime>[^\[\]]+)\] "(?P<protocol>[^"]+)" (?P<status>\d+) (?P<size>\d+) "(?P<url>http://[^"]+)" "(?P<useragent>[^"]+)"')
        with open(self.filename) as f:
            for line in f:
                line = line.strip()
                res = regex.match(line)
                if res:
                    d = res.groupdict()
                    for name, data in d.items():
                        self.res_dict[(name, data)] = self.res_dict.get(
                            (name, data), 0) + 1

    @lru_cache()  # 加入lru_cache避免同样的cmd多次执行handle
    def handle(self, cmd):
        time.sleep(2)  # 手动加入阻塞，显示lru_cache效果
        ret = list(filter(lambda x: x[0][0] == cmd, self.res_dict.items()))
        return ret  # 不能yield 因为yield循环一次就到头了

    def show(self, cmd):
        res = self.handle(cmd)
        total_count = 0

        for (name, data), count in res:
            print('{} appeared {} times'.format(data, count))
            total_count += count
            print('{} total_count is {}'.format(cmd, total_count))


d = Dispatcher('access_2021_02_22.log')
d.run()
while True:
    cmd = input('<<<').strip()
    if cmd in d.names:
        d.show(cmd)
    else:
        if cmd == 'quit':
            break
        else:
            print('unacceptable command {}'.format(cmd))
"""
完成的不错。不过如果按照这种方式的话，最好给用户提供下帮助，就是能打印帮助信息，要不然用户无法知道传入哪些命令获取的是哪些信息
"""
